home *** CD-ROM | disk | FTP | other *** search
Text File | 1995-03-22 | 45.0 KB | 1,317 lines |
- // copyright 1993 Michael B. Johnson; some portions copyright 1994, MIT
- // see COPYRIGHT for reuse legalities
- //
-
-
- #import "WW3DLight.h"
- #import "EveCommand.h"
- #import "WW3DAttributeState.h"
- #import "usefulWW3DFunctions.h"
-
- @implementation WW3DLight
-
-
- #define wwPI (3.1415926535897932384626433)
- #define DtoR (wwPI/180.0)
- #define RtoD (180.0/wwPI)
- #define toDegrees(r) ((r)*RtoD)
- #define toRadians(d) ((d)*DtoR)
- #define X_AXIS 1.0, 0.0, 0.0
- #define Y_AXIS 0.0, 1.0, 0.0
- #define Z_AXIS 0.0, 0.0, 1.0
-
-
- + initialize { [WW3DLight setVersion:1]; return self; }
-
- - init
- {
- [super init];
- visibleSizeScale = 1.0;
- visibleWhenPrinting = NO;
-
- xColor[0] = 1.0;
- xColor[1] = 0.0;
- xColor[2] = 0.0;
- yColor[0] = 0.0;
- yColor[1] = 1.0;
- yColor[2] = 0.0;
- zColor[0] = 0.0;
- zColor[1] = 0.0;
- zColor[2] = 1.0;
-
- innerConeOpacity[0] = 0.3;
- innerConeOpacity[1] = 0.3;
- innerConeOpacity[2] = 0.3;
- outerConeOpacity[0] = 0.1;
- outerConeOpacity[1] = 0.1;
- outerConeOpacity[2] = 0.1;
- beamOpacity[0] = intensity;
- beamOpacity[1] = intensity;
- beamOpacity[2] = intensity;
-
- xRotate = 0.0;
- yRotate = 0.0;
-
- NXConvertColorToRGB(color, &myRtColor[0], &myRtColor[1], &myRtColor[2]);
-
- return self;
- }
-
- - awake
- {
- [super awake];
- NXConvertColorToRGB(color, &myRtColor[0], &myRtColor[1], &myRtColor[2]);
- return self;
- }
-
- - copyFromZone:(NXZone *)zone { return [super copyFromZone:zone]; }
-
- - synchUpRotationValues
- {
- v[0] = from[0] - to[0];
- v[1] = from[1] - to[1];
- v[2] = from[2] - to[2];
- vMagnitude = sqrt((double)((v[0] * v[0]) + (v[1] * v[1]) + (v[2] * v[2])));
-
- u[0] = v[0]/vMagnitude;
- u[1] = v[1]/vMagnitude;
- u[2] = v[2]/vMagnitude;
-
- if (u[2] != 0.0)
- { yRotate = toDegrees(((RtFloat)atan((double)(u[0]/u[2]))));
- xRotate = toDegrees(( -1. * (RtFloat)atan((double)(u[1]/u[2]))));
- }
- else
- { yRotate = toDegrees(((RtFloat)atan((double)(u[0]))));
- xRotate = toDegrees((-1. * (RtFloat)atan((double)(u[1]))));
- }
-
- // NXLogError("from == (%f, %f, %f) : to== (%f, %f, %f)\n",
- // from[0], from[1], from[2], to[0], to[1], to[2]);
- // NXLogError("u == (%f, %f, %f) : xRotate == %f : yRotate == %f\n",
- // u[0], u[1], u[2], xRotate, yRotate);
-
- return self;
- }
-
- - (BOOL)on { return lightFlags.on; }
-
- - setColor:(NXColor)aColor
- {
- [super setColor:aColor];
- NXConvertColorToRGB(color, &myRtColor[0], &myRtColor[1], &myRtColor[2]);
- return self;
- }
-
- - ribCommands { return ribCommandList; }
- - appendRIBCommand:newRIBCommand
- {
- if ([newRIBCommand isKindOf:[EveCommand class]]) {
- hasEveCmd = YES;
- }
- [ribCommandList addObject:newRIBCommand];
- dirtyBoundingBox = YES;
- return self;
- }
-
-
- - renderSelfAsBox:(WW3DCamera *)camera startingAt:(RtFloat)shutterOpenTime endingAt:(RtFloat)shutterCloseTime
- {
- int i, howMany = [ribCommandList count];
-
-
- [super renderSelf:camera];
-
- for (i = 0; i < howMany; i++)
- { [(id <WWRenderable>)[ribCommandList objectAt:i] renderSelfAsBox:camera startingAt:shutterOpenTime endingAt:shutterCloseTime];
- }
-
- return self;
- }
-
- - renderSelf:(WW3DCamera *)camera startingAt:(RtFloat)shutterOpenTime endingAt:(RtFloat)shutterCloseTime
- {
- RtFloat length;
- int i, howMany = [ribCommandList count];
-
-
- [super renderSelf:camera];
-
-
- // uncomment this eventually, otherwise we'll always render the lights...
- //if ((NXDrawingStatus != NX_DRAWING) && !visibleWhenPrinting)
- //{ return self;
- //}
-
- RiAttributeBegin(); // this geometry and state that we don't really
- // want to foist on the light shader that this shape
- // actually represents, so we wrap all the following
- // in an AttributeBegin/End block.
-
- RiSurface("matte", RI_NULL); // force a reasonable, cheap shader
- // need to know if it's selected or not - if it is, draw as selected color otherwise use own color
- // for now, just color it...
- RiColor(myRtColor);
-
- switch (type)
- { case N3D_AmbientLight: // an ambient light is just a colored sphere of diameter 1
- RiSphere(visibleSizeScale * .5, visibleSizeScale * -.5, visibleSizeScale * .5, 360.0, RI_NULL);
- break;
- case N3D_PointLight: // a point light is six pointed star
- RiTranslate(from[0], from[1], from[2]);
- RiSphere(visibleSizeScale * .25, visibleSizeScale * -.25, visibleSizeScale * .25, 360.0, RI_NULL);
-
- RiColor(zColor);
- RiCylinder(visibleSizeScale * .05, 0, visibleSizeScale * .4, 360, RI_NULL);
- RiTranslate(0, 0, visibleSizeScale * .4);
- RiCone(visibleSizeScale * .1, visibleSizeScale * .1, 360, RI_NULL);
- RiTranslate(0, 0, visibleSizeScale * -0.4);
- RiRotate(-90, X_AXIS);
- RiColor(yColor);
- RiCylinder(visibleSizeScale * .05, 0, visibleSizeScale * .4, 360, RI_NULL);
- RiTranslate(0, 0, visibleSizeScale * 0.4);
- RiCone(visibleSizeScale * .1, visibleSizeScale * .1, 360, RI_NULL);
- RiTranslate(0, 0, visibleSizeScale * -0.4);
- RiRotate(-90, X_AXIS);
- RiColor(zColor);
- RiCylinder(visibleSizeScale * .05, 0, visibleSizeScale * .4, 360, RI_NULL);
- RiTranslate(0, 0, visibleSizeScale * 0.4);
- RiCone(visibleSizeScale * .1, visibleSizeScale * .1, 360, RI_NULL);
- RiTranslate(0, 0, visibleSizeScale * -0.4);
-
- RiRotate(-90, X_AXIS);
- RiColor(yColor);
- RiCylinder(visibleSizeScale * .05, 0, visibleSizeScale * .4, 360, RI_NULL);
- RiTranslate(0, 0, visibleSizeScale * 0.4);
- RiCone(visibleSizeScale * .1, visibleSizeScale * .1, 360, RI_NULL);
- RiTranslate(0, 0, visibleSizeScale * -0.4);
-
- RiRotate(-90, X_AXIS);
- RiRotate(90, Y_AXIS);
- RiColor(xColor);
- RiCylinder(visibleSizeScale * .05, 0, visibleSizeScale * .4, 360, RI_NULL);
- RiTranslate(0, 0, visibleSizeScale * 0.4);
- RiCone(visibleSizeScale * .1, visibleSizeScale * .1, 360, RI_NULL);
- RiTranslate(0, 0, visibleSizeScale * -0.4);
-
- RiRotate(180, Y_AXIS);
- RiColor(xColor);
- RiCylinder(visibleSizeScale * .05, 0, visibleSizeScale * .4, 360, RI_NULL);
- RiTranslate(0, 0, visibleSizeScale * 0.4);
- RiCone(visibleSizeScale * .1, visibleSizeScale * .1, 360, RI_NULL);
- break;
- case N3D_DistantLight: // this looks like a normalized arrow
- RiTranslate(from[0], from[1], from[2]);
- RiRotate(yRotate, Y_AXIS);
- RiRotate(xRotate, X_AXIS);
-
- RiRotate(180, Y_AXIS); // flip around to point Z at toPoint
- RiCylinder(visibleSizeScale * .1, 0, visibleSizeScale * .8, 360, RI_NULL);
- RiTranslate(0, 0, visibleSizeScale * .8);
- RiCone(visibleSizeScale * .2, visibleSizeScale * .2, 360, RI_NULL);
- break;
- case N3D_SpotLight: // two cones and an arrow pointing out
- RiTranslate(from[0], from[1], from[2]);
- RiRotate(yRotate, Y_AXIS);
- RiRotate(xRotate, X_AXIS);
- RiTranslate(0.0, 0.0, -1.0 * visibleSizeScale);
-
- RiOpacity(outerConeOpacity);
- RiCone(visibleSizeScale, visibleSizeScale * tan((double)((wwPI/180.0) * coneAngle)), 360, RI_NULL);
- RiOpacity(innerConeOpacity);
- RiCone(visibleSizeScale, visibleSizeScale * tan((double)((wwPI/180.0) * (coneAngle - coneDelta))), 360, RI_NULL);
-
- // need to represent the beam distribution
- RiOpacity(beamOpacity);
- RiTranslate(0.0, 0.0, visibleSizeScale);
- RiRotate(180, Y_AXIS); // flip around to point Z at toPoint
- length = (beamDistribution * visibleSizeScale * .8);
- RiCylinder(visibleSizeScale * .01, 0, length, 360, RI_NULL);
- RiTranslate(0, 0, length);
- RiCone(length * .2, length * .05, 360, RI_NULL);
- break;
- default: // complain
- break;
- }
- RiAttributeEnd();
-
- for (i = 0; i < howMany; i++)
- { [(id <WWRenderable>)[ribCommandList objectAt:i] renderSelf:camera startingAt:shutterOpenTime endingAt:shutterCloseTime];
- }
-
- return self;
- }
-
- - renderSelf:(WW3DCamera *)camera
- {
- RtFloat shutterOpenTime = [camera shutterOpenTime],
- shutterCloseTime = [camera shutterCloseTime];
-
-
- return [self renderSelf:camera startingAt:shutterOpenTime endingAt:shutterCloseTime];
- }
-
- - makePointFrom:(RtPoint)pf intensity:(RtFloat)i
- {
- [super makePointFrom:pf intensity:i];
- beamOpacity[0] = intensity;
- beamOpacity[1] = intensity;
- beamOpacity[2] = intensity;
- return [self synchUpRotationValues];
- }
-
- - makeDistantFrom:(RtPoint)pf to:(RtPoint)pt intensity:(RtFloat)i
- {
- [super makeDistantFrom:pf to:pt intensity:i];
- beamOpacity[0] = intensity;
- beamOpacity[1] = intensity;
- beamOpacity[2] = intensity;
- return [self synchUpRotationValues];
- }
-
- - makeSpotFrom:(RtPoint)pf to:(RtPoint)pt
- coneAngle:(RtFloat)ca coneDelta:(RtFloat)cd
- beamDistribution:(RtFloat)bd
- intensity:(RtFloat)i
- {
- [super makeSpotFrom:pf to:pt coneAngle:ca coneDelta:cd beamDistribution:bd intensity:i];
- beamOpacity[0] = intensity;
- beamOpacity[1] = intensity;
- beamOpacity[2] = intensity;
- return [self synchUpRotationValues];
-
- }
-
-
- - setFrom:(RtPoint)pf
- {
- [super setFrom:pf];
- return [self synchUpRotationValues];
- }
-
-
- - setFrom:(RtPoint)pf to:(RtPoint)pt
- {
- [super setFrom:pf to:pt];
- return [self synchUpRotationValues];
- }
-
- - setIntensity:(RtFloat)i
- {
- [super setIntensity:i];
- beamOpacity[0] = intensity;
- beamOpacity[1] = intensity;
- beamOpacity[2] = intensity;
- return [self synchUpRotationValues];
- }
-
- - transformCTM:(WW3DAttributeState *)attributeState startingAt:(RtFloat)shutterOpenTime endingAt:(RtFloat)shutterCloseTime
- { NXLogError("why are you calling transformCTM:startingAt:endingAt: for WW3DShape <%s>?\n", [self shapeName]);
- return self;
- }
-
- - (BOOL)isSelectable { return YES; } // This is a N3DKit thing, not mine
-
- - (BOOL)isLerpable { return NO; }
- - lerpWith:b by:(float)uValue { return self; }
- - lerpSelfWith:b by:(float)uValue { return self; }
-
- - (BOOL)isMotionBlurrable { return YES; } // this isn't strictly true, ya know...
-
- - (BOOL)isCompoundCommand { return YES; } // this isn't strictly true, ya know...
-
- - (BOOL)hasBoundingBox { return YES; } // this isn't strictly true, ya know...
-
- - (float)lastSampleIsAt
- {
- float oldestSample = 0.0, newSample;
- int i, howMany = [ribCommandList count];
-
-
- for (i = 0; i < howMany; i++)
- { newSample = [(id <WWRenderable>)[ribCommandList objectAt:i] lastSampleIsAt];
- if (newSample > oldestSample)
- { oldestSample = newSample;
- }
- }
-
- newSample = [descendant lastSampleIsAt];
- if (newSample > oldestSample)
- { oldestSample = newSample;
- }
-
- newSample = [nextPeer lastSampleIsAt];
- if (newSample > oldestSample)
- { oldestSample = newSample;
- }
-
- return oldestSample;
- }
-
- - (unsigned long int)maxSampleBandwidth;
- {
- unsigned long int maxSampleBandwidth = 50; //WAVE FIX ME
- int i, howMany = [ribCommandList count];
-
-
- for (i = 0; i < howMany; i++)
- { maxSampleBandwidth += [(id <WWRenderable>)[ribCommandList objectAt:i] maxSampleBandwidth];
- }
-
- maxSampleBandwidth += [descendant maxSampleBandwidth];
- maxSampleBandwidth += [nextPeer maxSampleBandwidth];
-
- return maxSampleBandwidth;
- }
-
-
- - (BOOL)isMoot
- {
- return NO;
- }
-
- - (BOOL)isMootStartingAt:(float)startTime endingAt:(float)endTime { return [self isMoot]; }
-
- - (BOOL)theSameAs:otherRIBCommand
- {
- return NO;
- }
-
- - (BOOL)similarTo:otherRIBCommand
- {
- if ([self class] != [otherRIBCommand class])
- { return NO;
- }
- return YES;
- }
-
-
- - renderMaps:(WW3DCamera *)camera startingAt:(RtFloat)shutterOpenTime endingAt:(RtFloat)shutterCloseTime usingStream:(NXStream *)ns
- {
- int i, howMany = [ribCommandList count];
-
-
- for (i = 0; i < howMany; i++)
- { [(id <WWRenderable>)[ribCommandList objectAt:i] renderMaps:camera startingAt:shutterOpenTime endingAt:shutterCloseTime usingStream:ns];
- }
- [descendant renderMaps:camera startingAt:shutterOpenTime endingAt:shutterCloseTime usingStream:ns];
- [nextPeer renderMaps:camera startingAt:shutterOpenTime endingAt:shutterCloseTime usingStream:ns];
-
- return self;
- }
-
-
- - renderMaps:(WW3DCamera *)camera usingStream:(NXStream *)ns
- {
- int i, howMany = [ribCommandList count];
- RtFloat shutterOpenTime = [camera shutterOpenTime],
- shutterCloseTime = [camera shutterCloseTime];
-
-
- for (i = 0; i < howMany; i++)
- { [(id <WWAnimatable>)[ribCommandList objectAt:i] renderMaps:camera startingAt:shutterOpenTime endingAt:shutterCloseTime usingStream:ns];
- }
- [descendant renderMaps:camera startingAt:shutterOpenTime endingAt:shutterCloseTime usingStream:ns];
- [nextPeer renderMaps:camera startingAt:shutterOpenTime endingAt:shutterCloseTime usingStream:ns];
-
- return self;
- }
-
-
-
- - renderMaps:(WW3DCamera *)camera startingAt:(RtFloat)shutterOpenTime endingAt:(RtFloat)shutterCloseTime
- {
- int i, howMany = [ribCommandList count];
-
-
- for (i = 0; i < howMany; i++)
- { [(id <WWRenderable>)[ribCommandList objectAt:i] renderMaps:camera startingAt:shutterOpenTime endingAt:shutterCloseTime];
- }
- [descendant renderMaps:camera startingAt:shutterOpenTime endingAt:shutterCloseTime];
- [nextPeer renderMaps:camera startingAt:shutterOpenTime endingAt:shutterCloseTime];
-
- return self;
- }
-
-
- - renderMaps:(WW3DCamera *)camera
- {
- int i, howMany = [ribCommandList count];
- RtFloat shutterOpenTime = [camera shutterOpenTime],
- shutterCloseTime = [camera shutterCloseTime];
-
-
- for (i = 0; i < howMany; i++)
- { [(id <WWAnimatable>)[ribCommandList objectAt:i] renderMaps:camera startingAt:shutterOpenTime endingAt:shutterCloseTime];
- }
- [descendant renderMaps:camera startingAt:shutterOpenTime endingAt:shutterCloseTime];
- [nextPeer renderMaps:camera startingAt:shutterOpenTime endingAt:shutterCloseTime];
-
- return self;
- }
-
-
-
-
- - (BOOL)pushesOrPopsCTM { return NO; }
- - (BOOL)pushesCTM { return NO; }
- - (BOOL)popsCTM { return NO; }
-
-
- - addChild:newChild
- {
- id oldDescendant = nil,
- oldDescendantList = [[List alloc] init],
- parentShape = self;
-
-
- // I think I want to unlink the old descendant, link the child in as
- // the new one, and then make the oldDescendant the peer of the child.
- oldDescendant = [parentShape descendant];
- if (oldDescendant)
- { while (oldDescendant)
- { [oldDescendantList addObject:oldDescendant];
- [oldDescendant unlink];
- oldDescendant = [parentShape descendant];
- }
- }
- [parentShape linkDescendant:newChild];
- if (oldDescendantList)
- { oldDescendant = [oldDescendantList objectAt:0];
- while (oldDescendant)
- { [newChild linkPeer:oldDescendant];
- [oldDescendantList removeObjectAt:0];
- oldDescendant = [oldDescendantList objectAt:0];
- }
- [oldDescendantList free];
- }
- dirtyBoundingBox = YES;
-
- return self;
- }
-
-
- - siblings
- {
- id currentPeer;
-
-
- // Really should cache this by trapping all the hierarchy frobbing and
- // having a dirty bit set. For right now, recalculate each time.
-
- [siblingList empty];
-
- if (self != [self firstPeer])
- { [siblingList addObject:[self firstPeer]];
- currentPeer = [self firstPeer];
-
- while ([currentPeer nextPeer])
- { [siblingList addObject:[currentPeer nextPeer]];
- currentPeer = [currentPeer nextPeer];
- }
- }
-
- return siblingList;
- }
-
- - children
- {
- id currentPeer;
-
-
- // Really should cache this by trapping all the hierarchy frobbing and
- // having a dirty bit set. For right now, recalculate each time.
-
- [childList empty];
-
- [childList addObject:[self descendant]];
- currentPeer = descendant;
- // note that the descendant is the firstPeer of it's siblings...
- while ([currentPeer nextPeer])
- { [childList addObject:[currentPeer nextPeer]];
- currentPeer = [currentPeer nextPeer];
- }
-
- return childList;
- }
-
- - parent { return ancestor; }
-
- - (unsigned short)pathSeparator { return pathSeparator; }
- - setPathSeparator:(unsigned short)newSeparator { pathSeparator = newSeparator; return self; }
-
-
- - getChildGivenPath:(const char *)path
- {
- char *part = (char *)path;
- int cnt, howMany, i;
- id ret;
-
-
- // the string looks something like "/foo/bar/zap/zow"
- // if the whole string is "/", return yourself
- // if the first part doesn't match your name, return nil.
- // if what's left after the first part is nil, return self;
- // if you're still here, send the message to each child until it doesn't return nil.
- // if you get through all your children and it still returns nil, return nil.
-
- if ((strlen(path) == 1) && ((unsigned short)(*part) == pathSeparator))
- { return self;
- }
-
- while (*part && ((unsigned short)(*part) != pathSeparator)) { part++; }
- // from "/foo/bar" to "/bar" or from "/foo" to ""
- cnt = part - (path + 1);
- if (!cnt) { return nil; } // catch the "/foo" to "" case
-
- if (!strncmp((path+1), [self shapeName], cnt))
- { // the first part is my name
- if (!*part) { return self; }// if there isn't anything else, I'm who they're looking for
-
- // otherwise, send message to each child to see if it's them
- howMany = [childList count];
- i = 0;
- while (i < howMany)
- { ret = [[childList objectAt:i] getChildGivenPath:part];
- if (ret)
- { return ret;
- }
- i++;
- }
- }
- // that isn't my name at the beginning - this isn't for me or any of my kids
- return nil;
- }
-
- - (char *)getPath
- {
- char *path, pathSeparatorString[2];
- int cnt = 1,
- i;
- id theShape;
- List *myShapeList;
-
-
- myShapeList = [[List alloc] init];
- theShape = self;
- while (theShape)
- { cnt += 2 + strlen([theShape shapeName]);
- [myShapeList addObject:theShape];
- theShape = [theShape ancestor];
- }
-
- path = malloc(cnt);
- if (!path)
- { [myShapeList free];
- return NULL;
- }
-
- path[0] = '\0';
- sprintf(pathSeparatorString, "%c", pathSeparator);
- for (i = [myShapeList count] - 1; i >= 0; i--)
- { strcat(path, pathSeparatorString);
- strcat(path, [[myShapeList objectAt:i] shapeName]);
- }
-
- return path;
- }
-
- - preRenderSelf:(WW3DCamera *)camera startingAt:(RtFloat)shutterOpenTime endingAt:(RtFloat)shutterCloseTime
- {
- int i, howMany = [ribCommandList count];
-
-
- for (i = 0; i < howMany; i++)
- { [(id <WWRenderable>)[ribCommandList objectAt:i] preRenderSelf:camera startingAt:shutterOpenTime endingAt:shutterCloseTime];
- }
- return self;
- }
-
-
- - preRenderSelf:(WW3DCamera *)camera
- {
- int i, howMany = [ribCommandList count];
- RtFloat shutterOpenTime = [camera shutterOpenTime],
- shutterCloseTime = [camera shutterCloseTime];
-
-
- for (i = 0; i < howMany; i++)
- { [(id <WWAnimatable>)[ribCommandList objectAt:i] preRenderSelf:camera startingAt:shutterOpenTime endingAt:shutterCloseTime];
- }
- return self;
- }
-
- - (RtBound *)boundingBoxStartingAt:(RtFloat)intervalStartTime endingAt:(RtFloat)intervalEndTime
- {
- if (dirtyBoundingBox)
- { [self calculateBoundingBoxStartingAt:intervalStartTime endingAt:intervalEndTime];
- }
- return &boundingBox;
- }
-
-
- - (int)findBoundingBoxFromRIBCommands:(int)startingIndex using:attributeState startingAt:(RtFloat)shutterOpenTime endingAt:(RtFloat)shutterCloseTime
- {
- RtBound tmpBoundingBox;
- RtMatrix tmpCTM;
- int i = startingIndex,
- incr,
- howMany = [ribCommandList count];
- id cmd;
- id newAttributeState;
-
-
- // first we need to find a bounding box to start with
- while (i < howMany)
- { cmd = [ribCommandList objectAt:i];
-
- // if the cmd pops the attribute stack, we're done.
- // we return how many commands we've gone through in our time here
- if ([cmd popsCTM])
- { return (i - startingIndex);
- }
-
- if ([cmd pushesCTM]) // here we go again...
- { newAttributeState = [[WW3DAttributeState alloc] init];
- i++;
- incr = [self findBoundingBoxFromRIBCommands:i using:newAttributeState startingAt:shutterOpenTime endingAt:shutterCloseTime];
- // we now need to merge this sub-attribute block into our current one
- if ([newAttributeState hasBoundingBox])
- { // This means that the bounding box in newAttributeState needs to be
- // transformed by the ctm of attributeState, and then we need to
- // "grow" to the current bound with that tranformed sub-bound.
-
- [attributeState getTransformMatrix:tmpCTM];
- WW3DDetermineBoundGivenBoundAndCTM(&tmpBoundingBox, [newAttributeState boundingBox], tmpCTM);
- [attributeState growBoundingBox:&tmpBoundingBox];
- }
- else
- { NXLogError("warning: WW3DLight <%s> has a moot set of commands at indices %d to %d\n", [self shapeName], (i - 1), (i + incr - 1));
- NXLogError("\tif there was a LightSource or AreaLight source in there, you can ignore this warning, though...\n");
- }
- i += incr;
- }
- else
- { [cmd transformCTM:attributeState startingAt:shutterOpenTime endingAt:shutterCloseTime];
- i++;
- }
-
- if ([cmd hasBoundingBox])
- { // great! we grow the bound of the current attribute state
- [attributeState growBoundingBox:[cmd boundingBoxStartingAt:shutterOpenTime endingAt:shutterCloseTime]];
- }
-
- }
- return (i - startingIndex);
- }
-
-
- - calculateBoundingBoxStartingAt:(RtFloat)shutterOpenTime endingAt:(RtFloat)shutterCloseTime
- {
- RtBound tmpBoundingBox;
- RtMatrix childMatrix, tmpCTM;
- int i, startingChildIndex = 0, howManyKids;
- id child, kids, newAttributeState;
-
-
- // this one is tricky. we'll need to be smart about this...
-
- // basically, each RIBCommand has it's own bounding box. We ask
- // each one in turn for it's boundingBox, and use that to build up ours.
- // Remember that each command is smart enough to know if any of it's
- // parameters have changed, but we need to be smart to realize if we have
- // rotated/translated/scaled. Recall that for scaling and translating we
- // can just add that to the boundingBox without asking everyone to recalculate,
- // but rotating mucks up everything.
-
- // so we need to transform these points against our 4x4, right?
- // Does the 3DKit take care of that for us? Hmmm...
-
- // Actually, I don't think we need to cat our 4x4 against it,
- // although I'm still unclear... Anyway, what we really want to do is
- // grovel over our ribCommandList and, to each object which answers YES
- // to hasBoundingBox we send the appropriate msg to get the bounding box
- // and compare it against ours.
-
- // actually, one more difficulty is that even though we might not
- // have any geometry (i.e. have any RIBCommands that respond
- // positively to -hasBoundingBox), we still might have some commands
- // transform the boundingBox, ie. do more than concatenate an identity
- // matrix against the matrix passed into -transform:.
-
- // what if you had 3 commands, the first two of which didn't have bounding boxes.
- // first time through, i == 1 at the end
- // next time, i == 2 at the end
- // final time through, i doesn't get incremented, but we are done
- // actually, it's more complicated than that.
- // some of these RIBCommands might not have a bounding box, but they do transform the CTM
- // also, you might have some transformational commands, then some geometry, then more
- // transformational commands, then geometry, then some more transformational... These
- // would all effect the children shapes in toto, but would also be affecting the
- // bounding box of the various geometry commands.
- // urgh...
-
- // It's not really so bad. Everything is taking place in the space of this shape, which
- // means that this shape's transformation matrix isn't consulted. We start off with
- // the identity matrix, and transform a tmp CTM (current transformation matrix) as we
- // move through the commands.
-
- // Actually, it's a bit trickier than you might think. The problem
- // is that although we have no fear of dropping down into a child until
- // we get to the list of kids, we just might hit a RIBAttributeBegin,
- // RIBTransformBegin, or RIBSolidBegin object, which would have the same effect
- // So, it looks like we need to extend the WWRenderable protocol to let us know
- // if the object pushes or pops the transformation stack. We'll need to recurse
- // down the transformation tree, building up the CTM, and transforming any bounding
- // box we find. We start off when the command pushes the stack. We cons up a new
- // CTM and set it to the Identity matrix. We then start walking down the commands,
- // first asking the command if it has a boundingBox. If it does, we set our bound
- // to it, and then transform the points in the bound by our CTM. We
- // then continue walking down the tree, asking each command if has a
- // bounding box, and if does, transforming that box by the CTM, and then
- // comparing it to our current bound, and growing it accordingly. If the
- // command doesn't have a bound, we just transform our CTM and our
- // current bound by it. We continue this until we get find a command
- // which pops the attribute stack. If, along the way, we hit a command which
- // actually pushes the stack, we need to recurse down and call this routine again.
- // The routine should be passed, and return, the id of a list of WW3DAttributeState
- // objects, which have a bounding box, a CTM, etc. in them.
-
- newAttributeState = [[WW3DAttributeState alloc] init];
- i = [self findBoundingBoxFromRIBCommands:0 using:newAttributeState startingAt:shutterOpenTime endingAt:shutterCloseTime];
- if (i != [ribCommandList count])
- { NXLogError("warning: shape <%s> has an unbalanced attribute delimiter at command %d (expected %d)\n",
- [self shapeName], i, [ribCommandList count]);
- return nil;
- }
-
- [newAttributeState getTransformMatrix:tmpCTM];
-
- if (![newAttributeState hasBoundingBox]) // this Shape has no real geometry in it, but it might have kids...
- { // we still need some approximation to start off with for this shape's bounding box.
- // to get it, we use our first child's bounding box.
- // if we don't have any kids, we just return.
- kids = [self children];
- if ([kids count] < 1)
- { dirtyBoundingBox = NO;
- return self;
- }
-
- // note that it's fair to assume that if we have children, each one has a bounding
- // box. If it didn't have a bounding box, that would mean it was a leaf node of
- // the tree without any geometry, which means we've got a moot node.
- child = [kids objectAt:0];
-
- // now, we can't just copy this bounding box, because it needs to
- // be transformed by the 4x4 that represents the transformation from this
- // shape to the child, i.e. it's 4x4.
- N3D_CopyBound(*([child boundingBoxStartingAt:shutterOpenTime endingAt:shutterCloseTime]), tmpBoundingBox);
-
- WW3DDetermineBoundGivenBoundAndCTM(&boundingBox, &tmpBoundingBox, tmpCTM);
-
- startingChildIndex = 1;
- }
- else
- { N3D_CopyBound(*([newAttributeState boundingBox]), boundingBox);
- }
-
- // at this point, we only have a bounding box for the geometry
- // associated with this shape's geometry. We now need to recurse down
- // our children, asking each to calculate it's bounding box. We then
- // compare that bounding box with our own, and update ours accordingly.
- // note that if we didn't have any geometry in this shape, we've already
- // looked at the boundingBox of our first child, and set our boundingBox
- // to that, so startingChildIndex has been incremented to 1, so we
- // don't waste time redoing that.
- kids = [self children];
- howManyKids = [kids count];
- for (i = startingChildIndex; i < howManyKids; i++)
- { child = [kids objectAt:i];
- N3D_CopyBound(*([child boundingBoxStartingAt:shutterOpenTime endingAt:shutterCloseTime]), tmpBoundingBox);
-
- // the boundingBox that we get from the child should already be transformed
- // correctly, right? Or do we also need to concat the child's transform
- // onto it? Yes, I think we do need to. We get the bound, convert it to points,
- // transform it against the child's CTM, then multiply *that* by the
- // tmpCTM (which takes into account transformational RIBCommands in this
- // shape, which will get executed before the child shape, and then
- // convert those points back to a bound. We can check that against
- // the current bound.
-
- // we need to transform that bounding box to reflect the transformational
- // commands that precede it in this shape's ribCommandList
- [child getTransformMatrix:childMatrix];
- WW3DDetermineBoundGivenBoundAndCTM(&tmpBoundingBox, &tmpBoundingBox, childMatrix);
- WW3DDetermineBoundGivenBoundAndCTM(&tmpBoundingBox, &tmpBoundingBox, tmpCTM);
-
- // now we should all be in the same space; compare against current boundingBox
- //// X
- if (tmpBoundingBox[0] < boundingBox[0])
- { boundingBox[0] = tmpBoundingBox[0];
- }
- if (tmpBoundingBox[1] > boundingBox[1])
- { boundingBox[1] = tmpBoundingBox[1];
- }
- //// Y
- if (tmpBoundingBox[2] < boundingBox[2])
- { boundingBox[2] = tmpBoundingBox[2];
- }
- if (tmpBoundingBox[3] > boundingBox[3])
- { boundingBox[3] = tmpBoundingBox[3];
- }
- //// Z
- if (tmpBoundingBox[4] < boundingBox[4])
- { boundingBox[4] = tmpBoundingBox[4];
- }
- if (tmpBoundingBox[5] > boundingBox[5])
- { boundingBox[5] = tmpBoundingBox[5];
- }
- }
-
- dirtyBoundingBox = NO;
-
- return self;
- }
-
- // this is a private method, should only used by an instance on itself
- - setBoundingBox:(RtBound *)newBoundingBox { return self; }
-
-
- - (BOOL)matricesAreEqual:(RtMatrix)m1 :(RtMatrix)m2
- {
- if (m1[0][0] != m2[0][0]) { return NO; }
- if (m1[0][1] != m2[0][1]) { return NO; }
- if (m1[0][2] != m2[0][2]) { return NO; }
- if (m1[0][3] != m2[0][3]) { return NO; }
-
- if (m1[1][0] != m2[1][0]) { return NO; }
- if (m1[1][1] != m2[1][1]) { return NO; }
- if (m1[1][2] != m2[1][2]) { return NO; }
- if (m1[1][3] != m2[1][3]) { return NO; }
-
- if (m1[2][0] != m2[2][0]) { return NO; }
- if (m1[2][1] != m2[2][1]) { return NO; }
- if (m1[2][2] != m2[2][2]) { return NO; }
- if (m1[2][3] != m2[2][3]) { return NO; }
-
- if (m1[3][0] != m2[3][0]) { return NO; }
- if (m1[3][1] != m2[3][1]) { return NO; }
- if (m1[3][2] != m2[3][2]) { return NO; }
- if (m1[3][3] != m2[3][3]) { return NO; }
-
- return YES;
- }
-
-
- - (BOOL)isIdentityMatrix:(RtMatrix)m { return [self matricesAreEqual:(RtFloat (*)[4])N3DIdentityMatrix :m]; }
-
- - writeEve:(NXStream *)stream atTabLevel:(int)tab
- {
- RtMatrix aMatrix;
- int i, howManySpaces, howMany = [ribCommandList count];
- id aCmd;
-
-
- for (i = 0; i < tab; i++)
- { NXPrintf(stream, "\t");
- }
- NXPrintf(stream, "startShape {%s} ", [self shapeName]);
- [self getTransformMatrix:aMatrix];
- if ([self isIdentityMatrix:aMatrix])
- { NXPrintf(stream, ";\n");
- }
- else // need to add the transformation matrix, since it's not the identity matrix...
- { NXPrintf(stream, "{");
- NXPrintf(stream, "%f %f %f %f ", aMatrix[0][0], aMatrix[0][1], aMatrix[0][2], aMatrix[0][3]);
- NXPrintf(stream, "\\\n"); // this is so we can have a new line that tcl won't see...
- // it would be nice if we put these on separate lines, but line up...
- // how far in do we need to go? well, first we need to tab the right amount, and then
- // move over "startShape " + strlen([self shapeName]) + "{"....
- for (i = 0; i < tab; i++)
- { NXPrintf(stream, "\t");
- }
- howManySpaces = strlen("startShape ") + strlen([self shapeName]) + strlen(" {");
-
- for (i = 0; i < howManySpaces; i++)
- { NXPrintf(stream, " ");
- }
- NXPrintf(stream, "%f %f %f %f ", aMatrix[1][0], aMatrix[1][1], aMatrix[1][2], aMatrix[1][3]);
- NXPrintf(stream, "\\\n"); // this is so we can have a new line that tcl won't see...
-
- for (i = 0; i < tab; i++)
- { NXPrintf(stream, "\t");
- }
- for (i = 0; i < howManySpaces; i++)
- { NXPrintf(stream, " ");
- }
- NXPrintf(stream, "%f %f %f %f ", aMatrix[2][0], aMatrix[2][1], aMatrix[2][2], aMatrix[2][3]);
- NXPrintf(stream, "\\\n"); // this is so we can have a new line that tcl won't see...
-
- for (i = 0; i < tab; i++)
- { NXPrintf(stream, "\t");
- }
- for (i = 0; i < howManySpaces; i++)
- { NXPrintf(stream, " ");
- }
- NXPrintf(stream, "%f %f %f %f};\n", aMatrix[3][0], aMatrix[3][1], aMatrix[3][2], aMatrix[3][3]);
- NXPrintf(stream, "\n");
- }
- // WAVE!!! Need to write out the rest of my shaders here!!!
- if (surfaceShader)
- { [surfaceShader writeEve:stream atTabLevel:(tab + 1)];
- NXPrintf(stream, "\n");
- }
-
- // okay, now tell all my rib commands to write themselves out...
- for (i = 0; i < howMany; i++)
- { aCmd = [ribCommandList objectAt:i];
- [aCmd writeEve:stream atTabLevel:(tab+1)];
- NXPrintf(stream, "\n");
- }
-
- // now tell my descendant to writeEve: itself...
- [descendant writeEve:stream atTabLevel:(tab + 1)];
- NXPrintf(stream, "\n");
-
- for (i = 0; i < tab; i++)
- { NXPrintf(stream, "\t");
- }
- NXPrintf(stream, "endShape\n");
-
- // now tell my nextPeer to writeEve: itself...
- [nextPeer writeEve:stream atTabLevel:tab];
-
- return self;
- }
-
- - writeScene:(NXStream *)stream atTabLevel:(int)tab
- {
- RtMatrix aMatrix;
- int i, howManySpaces, howMany = [ribCommandList count];
- id aCmd;
-
-
- for (i = 0; i < tab; i++)
- { NXPrintf(stream, "\t");
- }
- NXPrintf(stream, "startShape {%s} ", [self shapeName]);
- [self getTransformMatrix:aMatrix];
- if ([self isIdentityMatrix:aMatrix])
- { NXPrintf(stream, ";\n");
- }
- else // need to add the transformation matrix, since it's not the identity matrix...
- { NXPrintf(stream, "{");
- NXPrintf(stream, "%f %f %f %f ", aMatrix[0][0], aMatrix[0][1], aMatrix[0][2], aMatrix[0][3]);
- NXPrintf(stream, "\\\n"); // this is so we can have a new line that tcl won't see...
- // it would be nice if we put these on separate lines, but line up...
- // how far in do we need to go? well, first we need to tab the right amount, and then
- // move over "startShape " + strlen([self shapeName]) + "{"....
- for (i = 0; i < tab; i++)
- { NXPrintf(stream, "\t");
- }
- howManySpaces = strlen("startShape ") + strlen([self shapeName]) + strlen(" {");
-
- for (i = 0; i < howManySpaces; i++)
- { NXPrintf(stream, " ");
- }
- NXPrintf(stream, "%f %f %f %f ", aMatrix[1][0], aMatrix[1][1], aMatrix[1][2], aMatrix[1][3]);
- NXPrintf(stream, "\\\n"); // this is so we can have a new line that tcl won't see...
-
- for (i = 0; i < tab; i++)
- { NXPrintf(stream, "\t");
- }
- for (i = 0; i < howManySpaces; i++)
- { NXPrintf(stream, " ");
- }
- NXPrintf(stream, "%f %f %f %f ", aMatrix[2][0], aMatrix[2][1], aMatrix[2][2], aMatrix[2][3]);
- NXPrintf(stream, "\\\n"); // this is so we can have a new line that tcl won't see...
-
- for (i = 0; i < tab; i++)
- { NXPrintf(stream, "\t");
- }
- for (i = 0; i < howManySpaces; i++)
- { NXPrintf(stream, " ");
- }
- NXPrintf(stream, "%f %f %f %f};\n", aMatrix[3][0], aMatrix[3][1], aMatrix[3][2], aMatrix[3][3]);
- NXPrintf(stream, "\n");
- }
- // WAVE!!! Need to write out the rest of my shaders here!!!
- if (surfaceShader)
- { [surfaceShader writeScene:stream atTabLevel:(tab + 1)];
- NXPrintf(stream, "\n");
- }
-
- // okay, now tell all my rib commands to write themselves out...
- for (i = 0; i < howMany; i++)
- { aCmd = [ribCommandList objectAt:i];
- [aCmd writeScene:stream atTabLevel:(tab+1)];
- NXPrintf(stream, "\n");
- }
-
- // now tell my descendant to writeScene: itself...
- [descendant writeScene:stream atTabLevel:(tab + 1)];
- NXPrintf(stream, "\n");
-
- for (i = 0; i < tab; i++)
- { NXPrintf(stream, "\t");
- }
- NXPrintf(stream, "endShape\n");
-
- // now tell my nextPeer to writeScene: itself...
- [nextPeer writeScene:stream atTabLevel:tab];
-
- return self;
- }
-
-
- - write3DTextScene:(NXStream *)stream atTabLevel:(int)tab index:(int)index time:(float)time until:(float)lastTime
- {
- RtMatrix aMatrix;
- int i,
- howManySpaces, howMany = [ribCommandList count];
- id aCmd;
-
-
- for (i = 0; i < tab; i++)
- { NXPrintf(stream, "\t");
- }
-
- NXPrintf(stream, "startShape WW3DShape; ");
- // need tab
- // need index (position in current list)
- NXPrintf(stream,
- "EveCmd {Translate [expr { %d * $__text__(tabLength)}] [expr {$__text__(spacingFactor) * %d * $__text__(spacing) * $__text__(fontSize)}] 0 };\n",
- tab, index);
- for (i = 0; i < tab; i++)
- { NXPrintf(stream, "\t");
- }
- NXPrintf(stream, " EveCmd {WW3DText $__text__(fontName) $__text__(fontSize) {");
- NXPrintf(stream, "startShape %s ", [self shapeName]);
- [self getTransformMatrix:aMatrix];
- if ([self isIdentityMatrix:aMatrix])
- { NXPrintf(stream, " } left;\n");
- }
- else // need to add the transformation matrix, since it's not the identity matrix...
- { NXPrintf(stream, "{");
- NXPrintf(stream, "%f %f %f %f ", aMatrix[0][0], aMatrix[0][1], aMatrix[0][2], aMatrix[0][3]);
- NXPrintf(stream, "\\\n"); // this is so we can have a new line that tcl won't see...
- // it would be nice if we put these on separate lines, but line up...
- // how far in do we need to go? well, first we need to tab the right amount, and then
- // move over "startShape " + strlen([self shapeName]) + "{"....
- for (i = 0; i < tab; i++)
- { NXPrintf(stream, "\t");
- }
- howManySpaces = strlen("startShape ") + strlen([self shapeName]) + strlen(" {");
-
- for (i = 0; i < howManySpaces; i++)
- { NXPrintf(stream, " ");
- }
- NXPrintf(stream, "%f %f %f %f ", aMatrix[1][0], aMatrix[1][1], aMatrix[1][2], aMatrix[1][3]);
- NXPrintf(stream, "\\\n"); // this is so we can have a new line that tcl won't see...
-
- for (i = 0; i < tab; i++)
- { NXPrintf(stream, "\t");
- }
- for (i = 0; i < howManySpaces; i++)
- { NXPrintf(stream, " ");
- }
- NXPrintf(stream, "%f %f %f %f ", aMatrix[2][0], aMatrix[2][1], aMatrix[2][2], aMatrix[2][3]);
- NXPrintf(stream, "\\\n"); // this is so we can have a new line that tcl won't see...
-
- for (i = 0; i < tab; i++)
- { NXPrintf(stream, "\t");
- }
- for (i = 0; i < howManySpaces; i++)
- { NXPrintf(stream, " ");
- }
- NXPrintf(stream, "%f %f %f %f}} left;\n", aMatrix[3][0], aMatrix[3][1], aMatrix[3][2], aMatrix[3][3]);
- NXPrintf(stream, "\n");
- }
- NXPrintf(stream, "}\n");
-
- index++;
- // okay, next object - it will be a child of this shape:
- if (surfaceShader)
- { [surfaceShader write3DTextScene:stream atTabLevel:(tab+1) index:index++ time:time until:lastTime];
- NXPrintf(stream, "\n");
- }
-
- // okay, now tell all my rib commands to write themselves out...
- for (i = 0; i < howMany; i++)
- { aCmd = [ribCommandList objectAt:i];
- [aCmd write3DTextScene:stream atTabLevel:(tab+1) index:index++ time:time until:lastTime];
- NXPrintf(stream, "\n");
- }
-
- // now tell my descendant to writeEve: itself...
- [descendant write3DTextScene:stream atTabLevel:(tab+1) index:index++ time:time until:lastTime];
- NXPrintf(stream, "\n");
-
- // okay, now finish this text shape off by putting out the endShape
-
- for (i = 0; i < tab; i++)
- { NXPrintf(stream, "\t");
- }
- NXPrintf(stream, "startShape endShape; ");
- // need tab
- // need index (position in current list)
- NXPrintf(stream,
- "EveCmd {Translate [expr { %d * $__text__(tabLength)}] [expr {$__text__(spacingFactor) * %d * $__text__(spacing) * $__text__(fontSize)}] 0 };\n",
- tab, index);
- NXPrintf(stream, " EveCmd {WW3DText $__text__(fontName) $__text__(fontSize) {");
- NXPrintf(stream, "endShape");
- NXPrintf(stream, "} left;}\n");
-
- for (i = 0; i < tab; i++)
- { NXPrintf(stream, "\t");
- }
- NXPrintf(stream, "endShape;\n");
-
- for (i = 0; i < tab; i++)
- { NXPrintf(stream, "\t");
- }
- NXPrintf(stream, "endShape;\n"); // okay, end off the WW3DShape
-
-
- // now tell my nextPeer to writeEve: itself...
- [nextPeer write3DTextScene:stream atTabLevel:(tab+1) index:index time:time until:lastTime];
-
- return self;
- }
-
-
- - writeInventorAtTime:(float)currentTime to:(NXStream *)stream atTabLevel:(int)tab
- {
- RtMatrix aMatrix;
- int i, newTab, howMany = [ribCommandList count];
- id aCmd;
-
-
- for (i = 0; i < tab; i++)
- { NXPrintf(stream, "\t");
- }
- NXPrintf(stream, "# startShape {%s}\n", [self shapeName]);
- for (i = 0; i < tab; i++)
- { NXPrintf(stream, "\t");
- }
- NXPrintf(stream, "DEF \"%s\" Separator {\n", [self shapeName]);
- [self getTransformMatrix:aMatrix];
- if (![self isIdentityMatrix:aMatrix])
- {
-
- for (i = 0; i < (tab+1); i++)
- { NXPrintf(stream, "\t");
- }
- NXPrintf(stream, "MatrixTransform {\n");
- for (i = 0; i < (tab+2); i++)
- { NXPrintf(stream, "\t");
- }
- NXPrintf(stream, "matrix %f %f %f %f\n", aMatrix[0][0], aMatrix[0][1], aMatrix[0][2], aMatrix[0][3]);
- for (i = 0; i < (tab+2); i++)
- { NXPrintf(stream, "\t");
- }
- NXPrintf(stream, " %f %f %f %f\n", aMatrix[1][0], aMatrix[1][1], aMatrix[1][2], aMatrix[1][3]);
- for (i = 0; i < (tab+2); i++)
- { NXPrintf(stream, "\t");
- }
- NXPrintf(stream, " %f %f %f %f\n", aMatrix[2][0], aMatrix[2][1], aMatrix[2][2], aMatrix[2][3]);
- for (i = 0; i < (tab+2); i++)
- { NXPrintf(stream, "\t");
- }
- NXPrintf(stream, " %f %f %f %f\n", aMatrix[3][0], aMatrix[3][1], aMatrix[3][2], aMatrix[3][3]);
- for (i = 0; i < (tab+1); i++)
- { NXPrintf(stream, "\t");
- }
- NXPrintf(stream, "}\n");
- }
- // WAVE!!! Need to write out the rest of my shaders here!!!
- if (surfaceShader)
- { [surfaceShader writeInventorAtTime:currentTime to:stream atTabLevel:(tab + 1)];
- NXPrintf(stream, "\n");
- }
- if (displacementShader)
- { [displacementShader writeInventorAtTime:currentTime to:stream atTabLevel:(tab + 1)];
- NXPrintf(stream, "\n");
- }
-
- // okay, now tell all my rib commands to write themselves out...
- newTab = tab + 1;
- for (i = 0; i < howMany; i++)
- { aCmd = [ribCommandList objectAt:i];
- if (![aCmd isMootStartingAt:currentTime endingAt:currentTime])
- { if ([aCmd popsCTM])
- { newTab--;
- }
- [aCmd writeInventorAtTime:currentTime to:stream atTabLevel:newTab];
- if ([aCmd pushesCTM])
- { newTab++;
- }
- NXPrintf(stream, "\n");
- }
- }
-
- // now tell my descendant to writeInventor: itself...
- aCmd = [ribCommandList objectAt:i];
- if (![aCmd isMootStartingAt:currentTime endingAt:currentTime])
- { [descendant writeInventorAtTime:currentTime to:stream atTabLevel:(tab + 1)];
- NXPrintf(stream, "\n");
- }
-
- for (i = 0; i < tab; i++)
- { NXPrintf(stream, "\t");
- }
- NXPrintf(stream, "}\n");
-
- // now tell my nextPeer to writeInventor: itself...
- [nextPeer writeInventorAtTime:currentTime to:stream atTabLevel:tab];
-
- return self;
- }
-
-
- #define typeVector "fcfffffffff"
- #define typeValues &visibleSizeScale, &visibleWhenPrinting, \
- &a, &b, &c, &d, &vMagnitude, &cosOfAlpha, &sinOfAlpha, &xRotate, &yRotate
-
- - read:(NXTypedStream *)stream
- {
- int version;
-
- [super read:stream];
-
- NX_DURING
- version = NXTypedStreamClassVersion(stream, "WW3DLight");
- if (version == 1)
- { NXReadTypes(stream, typeVector, typeValues);
- NXReadArray(stream, "f", 3, v);
- NXReadArray(stream, "f", 3, u);
- NXReadArray(stream, "f", 3, uPrime);
- NXReadArray(stream, "f", 3, innerConeOpacity);
- NXReadArray(stream, "f", 3, outerConeOpacity);
- NXReadArray(stream, "f", 3, beamOpacity);
- }
- NX_HANDLER
- NXLogError("in read: %s, exception [%d] raised.\n", [[self class] name], NXLocalHandler.code);
- return nil;
- NX_ENDHANDLER
- return self;
- }
-
- - write:(NXTypedStream *)stream
- {
- [super write:stream];
- NXWriteTypes(stream, typeVector, typeValues);
- NXWriteArray(stream, "f", 3, v);
- NXWriteArray(stream, "f", 3, u);
- NXWriteArray(stream, "f", 3, uPrime);
- NXWriteArray(stream, "f", 3, innerConeOpacity);
- NXWriteArray(stream, "f", 3, outerConeOpacity);
- NXWriteArray(stream, "f", 3, beamOpacity);
- return self;
- }
-
- // boy, this is dumb... This is to get around the stupid warnings from the compiler - ask wave for details
- - class { return [super class]; }
-
- @end
-